package com.ssy.lingxi.contract.serviceimpl;

import cn.hutool.core.util.StrUtil;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.contract.constant.Constants;
import com.ssy.lingxi.contract.constant.SignConstant;
import com.ssy.lingxi.contract.entity.SignatureLog;
import com.ssy.lingxi.contract.esign.api.SignApi;
import com.ssy.lingxi.contract.esign.constant.EsignConstants;
import com.ssy.lingxi.contract.esign.exception.EsignException;
import com.ssy.lingxi.contract.esign.request.*;
import com.ssy.lingxi.contract.esign.response.*;
import com.ssy.lingxi.contract.esign.util.ApiUtil;
import com.ssy.lingxi.contract.model.bo.sign.SignAuthDetailBO;
import com.ssy.lingxi.contract.model.bo.sign.SignFlowBO;
import com.ssy.lingxi.contract.model.bo.sign.SignFlowNotifyBO;
import com.ssy.lingxi.contract.model.constant.sign.SignatureLogStateEnum;
import com.ssy.lingxi.contract.model.vo.sign.request.RevokeSignRequest;
import com.ssy.lingxi.contract.repository.SignatureLogRepository;
import com.ssy.lingxi.contract.service.ISignatureService;
import com.ssy.lingxi.contract.service.ISignatureUserDetailService;
import com.ssy.lingxi.contract.utils.FileUtils;
import com.ssy.lingxi.feign.UploadControllerFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;

/**
 * 电子签章服务实现类
 * @author yzc
 * @version 2.0.0
 * @date 2020/9/1
 */
@Slf4j
@Service
public class SignatureServiceImpl extends BaseSignatureService implements ISignatureService {

    @Resource
    private SignatureLogRepository signatureLogRepository;
    @Resource
    private SignApi signApi;
    @Resource
    private ISignatureUserDetailService signatureUserDetailService;
    @Resource
    private UploadControllerFeign uploadControllerFeign;


    @Override
    public SignFlowBO signatureFlowCreate(SignAuthDetailBO leadingAuthDetail, SignAuthDetailBO laborAuthDetail, String contractName, String contractUrl) {
        // =================================合同文件上传创建=================================
        // 获取合同模板文件信息
        byte[] bytes = FileUtils.fileDownload(contractUrl);
        if (bytes.length <= 0) {
            throw new BusinessException(ResponseCode.CONTRACT_READ_CONTRACT_FAIL);
        }

        // 加签文件数据
        String md5Base64 = ApiUtil.fileMd5(bytes);
        FileUploadCreateRequest fileUploadCreateRequest = FileUploadCreateRequest.builder()
                .contentMd5(md5Base64)
                .contentType("application/pdf")
                .convert2Pdf(false)
                .fileName(contractName)
                .fileSize((long) bytes.length)
                .build();

        String fileId;
        try {
            FileUploadCreateResponse fileUploadCreateResponse = signApi.fileTemplate().fileUploadCreate(fileUploadCreateRequest);
            fileId = fileUploadCreateResponse.getFileId();

            // 上传文件
            signApi.fileTemplate().fileUpload(fileUploadCreateResponse.getUploadUrl(), md5Base64, bytes);
        } catch (EsignException e) {
            log.error("e签宝合同文件上传创建: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // =================================创建签署流程=================================
        SignFlowCreateRequest signFlowCreateRequest = this.getSignFlowCreateRequest(leadingAuthDetail);

        // 文件名称
        String fileName = StrUtil.subBefore(contractName, ".", false);

        SignFlowCreateRequest.ConfigInfoBean configInfoBean = new SignFlowCreateRequest.ConfigInfoBean();
        // 回调地址
        configInfoBean.setNoticeDeveloperUrl(signApi.getProperties().getNotifyUrl() + SignConstant.singFlowFinish);
        configInfoBean.setNoticeType(EsignConstants.NoticeType.SMS);

        // 设置自动归档
        signFlowCreateRequest.setAutoArchive(true);
        signFlowCreateRequest.setBusinessScene(fileName);
        signFlowCreateRequest.setConfigInfo(configInfoBean);

        String flowId;
        try {
            SignFlowResponse signFlowResponse = signApi.signFlow().signFlowCreate(signFlowCreateRequest);
            flowId = signFlowResponse.getFlowId();
        } catch (EsignException e) {
            log.error("e签宝创建签署流程: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // =================================流程文档添加=================================
        SignFlowDocumentsAddRequest.Doc doc = new SignFlowDocumentsAddRequest.Doc();
        doc.setFileId(fileId);

        SignFlowDocumentsAddRequest request = SignFlowDocumentsAddRequest.builder()
                .flowId(flowId)
                .docs(Collections.singletonList(doc))
                .build();

        try {
            signApi.signFlow().signFlowDocumentsAdd(request);
        } catch (EsignException e) {
            log.error("e签宝签署流添加文档: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 保存签章记录
        SignatureLog signatureLog = new SignatureLog();
        signatureLog.setFileId(fileId);
        signatureLog.setFlowId(flowId);
        signatureLog.setFileUrl(contractUrl);
        signatureLog.setState(SignatureLogStateEnum.SIGN_NOT.getCode());
        signatureLog.setCreateTime(System.currentTimeMillis());
        signatureLogRepository.saveAndFlush(signatureLog);

        // 甲方设置静默签署
        if (!signatureUserDetailService.silentSignAuth(leadingAuthDetail)) {
            throw new BusinessException(ResponseCode.CONTRACT_LEADING_SILENT_SIGN_AUTH_FAIL);
        }

        // 乙方设置静默签署
        if (!signatureUserDetailService.silentSignAuth(laborAuthDetail)) {
            throw new BusinessException(ResponseCode.CONTRACT_LABOR_SILENT_SIGN_AUTH_FAIL);
        }

        // 返回数据
        SignFlowBO signFlowBO = new SignFlowBO();
        signFlowBO.setFlowId(flowId);
        signFlowBO.setFileId(fileId);
        signFlowBO.setSignatureLogId(signatureLog.getId());

        return signFlowBO;
    }

    @Override
    public SignFlowBO signatureFlowCreateNotLocalConvertPdf(SignAuthDetailBO leadingAuthDetail, SignAuthDetailBO laborAuthDetail, String contractName, String contractUrl) {
        // =================================合同文件上传创建=================================
        // 获取合同模板文件信息
        byte[] bytes = FileUtils.fileDownload(contractUrl);
        if (bytes.length <= 0) {
            throw new BusinessException(ResponseCode.CONTRACT_READ_CONTRACT_FAIL);
        }

        // 加签文件数据
        String md5Base64 = ApiUtil.fileMd5(bytes);
        FileUploadCreateRequest fileUploadCreateRequest = FileUploadCreateRequest.builder()
                .contentMd5(md5Base64)
                .contentType("application/octet-stream")
                .convert2Pdf(true)
                .fileName(contractName)
                .fileSize((long) bytes.length)
                .build();

        String fileId;
        try {
            FileUploadCreateResponse fileUploadCreateResponse = signApi.fileTemplate().fileUploadCreate(fileUploadCreateRequest);
            fileId = fileUploadCreateResponse.getFileId();

            // 上传文件
            signApi.fileTemplate().fileUpload(fileUploadCreateResponse.getUploadUrl(), md5Base64, bytes, "application/octet-stream");
        } catch (EsignException e) {
            log.error("e签宝合同文件上传创建: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // =================================创建签署流程=================================
        SignFlowCreateRequest signFlowCreateRequest = this.getSignFlowCreateRequest(leadingAuthDetail);

        // 文件名称
        String fileName = StrUtil.subBefore(contractName, ".", false);

        SignFlowCreateRequest.ConfigInfoBean configInfoBean = new SignFlowCreateRequest.ConfigInfoBean();
        // 回调地址
        configInfoBean.setNoticeDeveloperUrl(signApi.getProperties().getNotifyUrl() + SignConstant.singFlowFinish);
        configInfoBean.setNoticeType(EsignConstants.NoticeType.SMS);

        // 设置自动归档
        signFlowCreateRequest.setAutoArchive(true);
        signFlowCreateRequest.setBusinessScene(fileName);
        signFlowCreateRequest.setConfigInfo(configInfoBean);

        String flowId;
        try {
            SignFlowResponse signFlowResponse = signApi.signFlow().signFlowCreate(signFlowCreateRequest);
            flowId = signFlowResponse.getFlowId();
        } catch (EsignException e) {
            log.error("e签宝创建签署流程: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 文档转换pdf进度
        try {
            Integer status = EsignConstants.fileStatus.upload_none;
            while (!EsignConstants.fileStatus.file_convert_complete.equals(status)) {
                FileStatusResponse fileStatusResponse = signApi.fileTemplate().fileStatus(fileId);
                status = fileStatusResponse.getStatus();
                log.info("e签宝文件转换查询文件状态, 状态值为: {}", status);
                Thread.sleep(1000);
            }
        } catch (EsignException e) {
            log.error("e签宝文件转换查询文件状态: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        } catch (InterruptedException e) {
            log.error("e签宝文件转换查询文件状态中断异常", e);
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // =================================流程文档添加=================================
        SignFlowDocumentsAddRequest.Doc doc = new SignFlowDocumentsAddRequest.Doc();
        doc.setFileId(fileId);

        SignFlowDocumentsAddRequest request = SignFlowDocumentsAddRequest.builder()
                .flowId(flowId)
                .docs(Collections.singletonList(doc))
                .build();

        try {
            signApi.signFlow().signFlowDocumentsAdd(request);
        } catch (EsignException e) {
            log.error("e签宝签署流添加文档: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 保存签章记录
        SignatureLog signatureLog = new SignatureLog();
        signatureLog.setFileId(fileId);
        signatureLog.setFlowId(flowId);
        signatureLog.setFileUrl(contractUrl);
        signatureLog.setState(SignatureLogStateEnum.SIGN_NOT.getCode());
        signatureLog.setCreateTime(System.currentTimeMillis());
        signatureLogRepository.saveAndFlush(signatureLog);

        // 甲方设置静默签署
        if (!signatureUserDetailService.silentSignAuth(leadingAuthDetail)) {
            throw new BusinessException(ResponseCode.CONTRACT_LEADING_SILENT_SIGN_AUTH_FAIL);
        }

        // 乙方设置静默签署
        if (!signatureUserDetailService.silentSignAuth(laborAuthDetail)) {
            throw new BusinessException(ResponseCode.CONTRACT_LABOR_SILENT_SIGN_AUTH_FAIL);
        }

        // 返回数据
        SignFlowBO signFlowBO = new SignFlowBO();
        signFlowBO.setFlowId(flowId);
        signFlowBO.setFileId(fileId);
        signFlowBO.setSignatureLogId(signatureLog.getId());

        return signFlowBO;
    }

    @Override
    public void firstSign(SignAuthDetailBO leadingAuthDetail, Long signatureLogId) {
        // 签章记录信息
        SignatureLog signatureLog = signatureLogRepository.findById(signatureLogId).orElse(null);
        if (Objects.isNull(signatureLog)) {
            throw new BusinessException(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        // =================================搜索盖章关键字=================================
        // 盖章关键字
        String keyword = this.getKeyword(leadingAuthDetail);
        List<WordsPositionSearchResponse> wordsPositionSearchResponses;
        try {
            wordsPositionSearchResponses = searchKeyWord(signatureLog.getFileId(), keyword);
        } catch (EsignException e) {
            log.error("e签宝甲方搜索盖章关键字: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 处理关键字坐标
        Map<String, WordsPositionSearchResponse.Position> keywordMap = handleKeyWordPosition(wordsPositionSearchResponses);
        BaseSignFieldRequest.BaseSignfield.PosBean posBean = handleLeftDownCoordinateList(keywordMap.get(keyword));

        // =================================添加甲方签署区=================================
        // 签署区请求实体
        SignFieldAutoRequest.Signfield signfieldsBean = this.getSignField(leadingAuthDetail);
        // 印章
        signfieldsBean.setSealId(this.getSealId(leadingAuthDetail));
        signfieldsBean.setPosBean(posBean);
        signfieldsBean.setFileId(signatureLog.getFileId());
        signfieldsBean.setSignDateBeanType(EsignConstants.SignDateBeanType.MUST);

        SignFieldAutoRequest signFieldAutoRequest = new SignFieldAutoRequest();
        signFieldAutoRequest.setFlowId(signatureLog.getFlowId());
        signFieldAutoRequest.setSignfields(Collections.singletonList(signfieldsBean));
        try {
            signApi.signFlow().signFieldAuto(signFieldAutoRequest);
        } catch (EsignException e) {
            log.error("e签宝甲方添加签署区: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 保存签章记录
        signatureLog = this.platformSignatureLog(leadingAuthDetail, signatureLog);
        signatureLogRepository.saveAndFlush(signatureLog);
    }

    @Override
    public void secondSign(SignAuthDetailBO laborAuthDetail, Long signatureLogId) {
        // 签章记录信息
        SignatureLog signatureLog = signatureLogRepository.findById(signatureLogId).orElse(null);
        if (Objects.isNull(signatureLog)) {
            throw new BusinessException(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        // =================================搜索盖章关键字=================================
        // 盖章关键字
        String keyword = this.getKeyword(laborAuthDetail);
        List<WordsPositionSearchResponse> wordsPositionSearchResponses;
        try {
            wordsPositionSearchResponses = searchKeyWord(signatureLog.getFileId(), keyword);
        } catch (EsignException e) {
            log.error("e签宝乙方搜索盖章关键字: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        Map<String, WordsPositionSearchResponse.Position> keywordMap = handleKeyWordPosition(wordsPositionSearchResponses);
        BaseSignFieldRequest.BaseSignfield.PosBean posBean = handleRightDownCoordinateList(keywordMap.get(keyword));

        // =================================添加乙方签署区=================================
        // 签署区请求实体
        SignFieldAutoRequest.Signfield signfieldsBean = this.getSignField(laborAuthDetail);
        // 印章
        signfieldsBean.setSealId(this.getSealId(laborAuthDetail));
        signfieldsBean.setPosBean(posBean);
        signfieldsBean.setFileId(signatureLog.getFileId());
        signfieldsBean.setSignDateBeanType(EsignConstants.SignDateBeanType.MUST);

        SignFieldAutoRequest signFieldAutoRequest = new SignFieldAutoRequest();
        signFieldAutoRequest.setFlowId(signatureLog.getFlowId());
        signFieldAutoRequest.setSignfields(Collections.singletonList(signfieldsBean));

        try {
            signApi.signFlow().signFieldAuto(signFieldAutoRequest);
        } catch (EsignException e) {
            log.error("e签宝乙方添加签署区: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 保存签章记录
        signatureLog = this.autoSignatureLog(laborAuthDetail, signatureLog);
        signatureLogRepository.saveAndFlush(signatureLog);
    }

    @Override
    public void setHandSign(SignAuthDetailBO signAuthDetailBO, Long signatureLogId) {
        // 签章记录信息
        SignatureLog signatureLog = signatureLogRepository.findById(signatureLogId).orElse(null);
        if (Objects.isNull(signatureLog)) {
            throw new BusinessException(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        // =================================添加甲方签署区=================================
        SignFieldHandSignRequest.Signfield signfield = this.getHandSignField(signAuthDetailBO, signatureLog.getFileId());
        SignFieldHandSignRequest request = new SignFieldHandSignRequest();
        request.setFlowId(signatureLog.getFlowId());
        request.setSignfields(Collections.singletonList(signfield));
        try {
//            SignFieldAutoResponse signFieldAutoResponse = signApi.signFlow().signFieldHandSign(request);
            signApi.signFlow().signFieldHandSign(request);
        } catch (EsignException e) {
            log.error("e签宝添加手动签署区: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 保存签章记录
        signatureLog = this.platformSignatureLog(signAuthDetailBO, signatureLog);
        signatureLogRepository.saveAndFlush(signatureLog);
    }

    @Override
    public void signStart(Long signatureLogId) {
        // =================================签署流程启动=================================
        // 签章记录信息
        SignatureLog signatureLog = signatureLogRepository.findById(signatureLogId).orElse(null);
        if (Objects.isNull(signatureLog)) {
            throw new BusinessException(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        try {
            signApi.signFlow().signFlowStart(signatureLog.getFlowId());
        } catch (EsignException e) {
            log.error("e签宝合同签署开启: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 更新签章记录信息
        signatureLog.setState(SignatureLogStateEnum.SIGNING.getCode());
        signatureLogRepository.saveAndFlush(signatureLog);
    }

    @Override
    public String getHandSignUrl(SignAuthDetailBO signAuthDetailBO, Long signatureLogId) {
        // 签章记录信息
        SignatureLog signatureLog = signatureLogRepository.findById(signatureLogId).orElse(null);
        if (Objects.isNull(signatureLog)) {
            throw new BusinessException(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        ExecuteUrlRequest request = this.getExecuteUrl(signAuthDetailBO, signatureLog.getFlowId());
        String url;
        try {
            ExecuteUrlResponse response = signApi.signFlow().executeUrl(request);
            url = response.getUrl();
        } catch (EsignException e) {
            System.out.println("e签宝获取签署地址: {}" + e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        return url;
    }

    @Override
    public Long oneStepSign(SignAuthDetailBO leadingAuthDetail, SignAuthDetailBO laborAuthDetail, String contractName, String contractUrl) {
        // 获取合同模板文件信息
        byte[] bytes = FileUtils.fileDownload(contractUrl);
        if (bytes.length <= 0) {
            throw new BusinessException(ResponseCode.CONTRACT_READ_CONTRACT_FAIL);
        }

        // 加签文件数据
        String md5Base64 = ApiUtil.fileMd5(bytes);

        String fileId;
        try {
            // 合同文件上传创建
            FileUploadCreateRequest fileUploadCreateRequest = FileUploadCreateRequest.builder()
                    .contentMd5(md5Base64)
                    .contentType("application/pdf")
                    .convert2Pdf(false)
                    .fileName(contractName)
                    .fileSize((long) bytes.length)
                    .build();
            FileUploadCreateResponse fileUploadCreateResponse = signApi.fileTemplate().fileUploadCreate(fileUploadCreateRequest);
            fileId = fileUploadCreateResponse.getFileId();

            // 上传文件
            signApi.fileTemplate().fileUpload(fileUploadCreateResponse.getUploadUrl(), md5Base64, bytes);
        } catch (EsignException e) {
            log.error("e签宝甲方签章: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 甲方设置静默签署
        if (!signatureUserDetailService.silentSignAuth(leadingAuthDetail)) {
            throw new BusinessException(ResponseCode.CONTRACT_LEADING_SILENT_SIGN_AUTH_FAIL);
        }

        // 乙方设置静默签署
        if (!signatureUserDetailService.silentSignAuth(laborAuthDetail)) {
            throw new BusinessException(ResponseCode.CONTRACT_LABOR_SILENT_SIGN_AUTH_FAIL);
        }

        // =================================甲方信息=================================
        // 甲方盖章关键字
        String firstName = this.getKeyword(leadingAuthDetail);

        // =================================乙方信息=================================
        // 乙方盖章关键字
        String secondName = this.getKeyword(laborAuthDetail);

        // =================================搜索盖章关键字=================================
        List<WordsPositionSearchResponse> wordsPositionSearchResponses;
        try {
            String keyword = firstName + "," + secondName;
            wordsPositionSearchResponses = searchKeyWord(fileId, keyword);
        } catch (EsignException e) {
            log.error("e签宝乙方签章: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }
        Map<String, WordsPositionSearchResponse.Position> keywordMap = handleKeyWordPosition(wordsPositionSearchResponses);

        // 待签署文档
        SignFlowCreateOneStepRequest.Doc doc = new SignFlowCreateOneStepRequest.Doc();
        doc.setFileId(fileId);
        doc.setFileName(contractName);

        // 任务配置信息
        SignFlowCreateOneStepRequest.FlowInfoBean.FlowConfigInfo flowConfigInfo = new SignFlowCreateOneStepRequest.FlowInfoBean.FlowConfigInfo();
        flowConfigInfo.setNoticeDeveloperUrl(signApi.getProperties().getNotifyUrl() + SignConstant.singFlowFinish);
        flowConfigInfo.setNoticeType(EsignConstants.NoticeType.SMS);

        // 文件名称
        String fileName = StrUtil.subBefore(contractName, ".", false);

        // 流程基本信息(甲方)
        SignFlowCreateOneStepRequest.FlowInfoBean flowInfoBean = this.getFlowInfo(leadingAuthDetail);
        flowInfoBean.setAutoArchive(true);
        flowInfoBean.setAutoInitiate(true);
        flowInfoBean.setBusinessScene(fileName);
        flowInfoBean.setFlowConfigInfo(flowConfigInfo);

        // ===============================甲方签署====================================
        // 甲方签章记录信息
        SignatureLog signatureLog = new SignatureLog();
        signatureLog = this.platformSignatureLog(leadingAuthDetail, signatureLog);

        // 签署文件信息
        SignFlowCreateOneStepRequest.Signer.Signfield.PosBean firstPosBean = handleOneStepLeftDownCoordinateList(keywordMap.get(firstName));
        SignFlowCreateOneStepRequest.Signer.Signfield firstSignfield = getOneStepSignField(leadingAuthDetail);
        firstSignfield.setAutoExecute(true);
        firstSignfield.setFileId(fileId);
        firstSignfield.setPosBean(firstPosBean);

        // 甲方签署信息
        SignFlowCreateOneStepRequest.Signer firstSigner = new SignFlowCreateOneStepRequest.Signer();
        SignFlowCreateOneStepRequest.Signer.SignerAccount firstSignerAccount = this.getOneStepSignerAccount(leadingAuthDetail);
        firstSigner.setSignerAccount(firstSignerAccount);
        firstSigner.setSignfields(Collections.singletonList(firstSignfield));

        // ===============================乙方签署====================================
        // 乙方签章记录信息
        signatureLog = this.autoSignatureLog(laborAuthDetail, signatureLog);

        // 签署文件信息
        SignFlowCreateOneStepRequest.Signer.Signfield.PosBean secondSignPosBean = handleOneStepRightDownCoordinateList(keywordMap.get(secondName));
        SignFlowCreateOneStepRequest.Signer.Signfield secondSignfield = getOneStepSignField(laborAuthDetail);
        secondSignfield.setAutoExecute(true);
        secondSignfield.setFileId(fileId);
        secondSignfield.setPosBean(secondSignPosBean);

        // 签署账号信息
        SignFlowCreateOneStepRequest.Signer secondSigner = new SignFlowCreateOneStepRequest.Signer();
        SignFlowCreateOneStepRequest.Signer.SignerAccount secondSignerAccount = this.getOneStepSignerAccount(laborAuthDetail);
        secondSigner.setSignerAccount(secondSignerAccount);
        secondSigner.setSignfields(Collections.singletonList(secondSignfield));

        List<SignFlowCreateOneStepRequest.Signer> signerList = new ArrayList<>();
        signerList.add(firstSigner);
        signerList.add(secondSigner);
        SignFlowCreateOneStepRequest oneStepRequest = SignFlowCreateOneStepRequest.builder()
                .docs(Collections.singletonList(doc))
                .flowInfo(flowInfoBean)
                .signers(signerList)
                .build();

        SignFlowResponse signFlowResponse;
        try {
            signFlowResponse = signApi.signFlow().signFlowCreateOneStep(oneStepRequest);
        } catch (EsignException e) {
            log.error("e签宝一步发起签署: {}", e.getError());
            throw new BusinessException(ResponseCode.CONTRACT_ESIGN_FAIL);
        }

        // 保存签章信息
        signatureLog.setFileId(fileId);
        signatureLog.setFileUrl(contractUrl);
        signatureLog.setFlowId(signFlowResponse.getFlowId());
        signatureLog.setState(SignatureLogStateEnum.SIGNING.getCode());
        signatureLogRepository.saveAndFlush(signatureLog);

        return signatureLog.getId();
    }

    @Override
    public Wrapper<Void> revokeSign(RevokeSignRequest request) {
        SignatureLog signatureLog = signatureLogRepository.findById(request.getSignatureLogId()).orElse(null);
        if (Objects.isNull(signatureLog)) {
            return Wrapper.fail(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        SignFlowRevokeRequest revokeRequest = SignFlowRevokeRequest.builder()
                .flowId(signatureLog.getFlowId())
                .operatorId(signatureLog.getPlatformAccountId())
                .revokeReason(request.getReason())
                .build();

        try {
            signApi.signFlow().signFlowRevoke(revokeRequest);
        } catch (EsignException e) {
            log.error("e签宝签署流程撤销: {}", e.getError());
            return Wrapper.fail(ResponseCode.CONTRACT_ESIGN_FAIL, e.getError().getErrMsg());
        }
        return Wrapper.success();
    }

    @Override
    public boolean updateSignResult(SignFlowUpdateNotifyRequest notifyRequest) {
        String flowId = notifyRequest.getFlowId();
        // 签署主体id
        String authorizedAccountId = notifyRequest.getAuthorizedAccountId();
        if (EsignConstants.SignResult.success.equals(notifyRequest.getSignResult())) {
            SignatureLog signatureLog = signatureLogRepository.findByFlowId(flowId);
            if (Objects.isNull(signatureLog)) {
                log.error("e签宝合同签署流程更新签署状态: 查询合同签署记录失败");
                return false;
            }

            if (signatureLog.getPlatformAccountId().equals(authorizedAccountId)) {
                signatureLog.setPlatformSignResult(signatureLog.getSignSignResult());
            } else {
                signatureLog.setSignSignResult(signatureLog.getSignSignResult());
            }
            signatureLogRepository.saveAndFlush(signatureLog);
        }
        return false;
    }

    @Override
    public boolean updateNotifySuccess(SignFlowNotifyBO notifyBO) {
        String flowId = notifyBO.getFlowId();
        SignatureLog signatureLog = signatureLogRepository.findByFlowId(flowId);
        if (Objects.isNull(signatureLog)) {
            log.error("e签宝合同签署流程文档下载: 查询合同签署记录失败");
            return false;
        }

        // 完成
        signatureLog.setState(SignatureLogStateEnum.SIGN_FINISH.getCode());
        signatureLog.setDescription(notifyBO.getStatusDescription());

        String saveFileUrl = notifyDownloadContractFile(notifyBO.getFlowId(), signatureLog.getFileId());
        // 保存合同地址
        if (Objects.nonNull(saveFileUrl)) {
            signatureLog.setFileUrl(saveFileUrl);
        }
        signatureLogRepository.saveAndFlush(signatureLog);

        // 更新订单合同地址(注: 生成订单前签署合同, 订单还没有保存数据,是找不到订单数据的)
//        ContractUrlSaveRequest contractUrlSaveRequest = new ContractUrlSaveRequest();
//        contractUrlSaveRequest.setSignatureLogId(signatureLog.getId());
//        contractUrlSaveRequest.setContractUrl(saveFileUrl);
//        Wrapper wrapper = purchaseOrderControllerFeign.contractUrlSave(contractUrlSaveRequest);
//        if (ResponseCode.SUCCESS.getCode() != wrapper.getCode()) {
//            log.error("合同签署更新订单合同地址失败: {}", wrapper.getMessage());
//        }

        return true;
    }

    @Override
    public boolean updateNotifyFail(SignFlowNotifyBO notifyBO) {
        String flowId = notifyBO.getFlowId();
        SignatureLog signatureLog = signatureLogRepository.findByFlowId(flowId);
        if (Objects.isNull(signatureLog)) {
            log.error("e签宝合同签署流程文档下载: 查询合同签署记录失败");
            return false;
        }
        // 撤销
        signatureLog.setState(SignatureLogStateEnum.SIGN_FAIL.getCode());
        signatureLog.setDescription(notifyBO.getStatusDescription());
        signatureLogRepository.saveAndFlush(signatureLog);
        return false;
    }

    private String notifyDownloadContractFile(String flowId, String fileId) {
        // 流程文档下载
        log.info("合同签署流程文档开始下载flowId:{} ......", flowId);
        SignFlowDocResponse signFlowDocResponse;
        try {
            signFlowDocResponse = signApi.signFlow().signFlowDocumentsDownload(flowId);
        } catch (EsignException e) {
            log.error("e签宝合同签署流程文档下载: {}", e.getError());
            return null;
        }

        SignFlowDocResponse.DocsBean doc = Optional.ofNullable(signFlowDocResponse.getDocs())
                .flatMap(docs -> docs.stream().filter(e -> fileId.equals(e.getFileId())).findFirst())
                .orElse(null);
        if (Objects.isNull(doc)) {
            return null;
        }

        byte[] bytes = FileUtils.fileDownload(doc.getFileUrl());
        if (bytes.length <= 0) {
            log.error("e签宝合同签署流程文档下载: 下载文件失败");
            return null;
        }

        MultipartFile multipartFile = FileUtils.createMultipartFile(bytes, Constants.contract_file_pdf_suffix);
        Wrapper<String> uploadResponse = uploadControllerFeign.upload(multipartFile);
        if (ResponseCode.SUCCESS.getCode() != uploadResponse.getCode()) {
            log.error("e签宝合同签署流程文档下载: 请求文件上传服务失败");
            return null;
        }

        return uploadResponse.getData();
    }

    /**
     * 查询关键字坐标
     * @param fileId 文件id
     * @param keyWords 关键词
     * @return 词位置搜索响应
     * @throws EsignException e签宝异常
     */
    private List<WordsPositionSearchResponse> searchKeyWord(String fileId, String keyWords) throws EsignException {
        WordsPositionSearchRequest searchRequest = WordsPositionSearchRequest.builder()
                .fileId(fileId)
                .keywords(keyWords)
                .build();

        return signApi.helper().wordsPositionSearch(searchRequest);
    }

    /**
     * 获取文件最后一页
     * @param wordsPositionSearchResponseList 词位置搜索响应
     * @return 获取文件最后一页
     */
    private Map<String, WordsPositionSearchResponse.Position> handleKeyWordPosition(List<WordsPositionSearchResponse> wordsPositionSearchResponseList) {
        Map<String, WordsPositionSearchResponse.Position> map = new HashMap<>();
        for (WordsPositionSearchResponse wordsPositionSearchResponse : wordsPositionSearchResponseList) {
            String keyword = wordsPositionSearchResponse.getKeyword();

            List<WordsPositionSearchResponse.Position> positionList = wordsPositionSearchResponse.getPositionList();
            // 获取最后一页
            WordsPositionSearchResponse.Position position = positionList.stream()
                    .max(Comparator.comparing(WordsPositionSearchResponse.Position::getPageIndex))
                    .orElseThrow(() -> new BusinessException(ResponseCode.CONTRACT_CONTRACT_KEYWORD_NOT_FOUND));

            map.put(keyword, position);
        }

        return map;
    }

    /**
     * 获取左下的关键字
     * @param position 位置
     * @return 左下的关键字
     */
    private BaseSignFieldRequest.BaseSignfield.PosBean handleLeftDownCoordinateList(WordsPositionSearchResponse.Position position) {
        List<WordsPositionSearchResponse.Position.Coordinate> coordinateList = position.getCoordinateList();
        // 最下
        WordsPositionSearchResponse.Position.Coordinate minPoyCoordinate = coordinateList.get(0);
        for (WordsPositionSearchResponse.Position.Coordinate coordinate : coordinateList) {
            if (minPoyCoordinate.getPosy() > coordinate.getPosy()) {
                minPoyCoordinate = coordinate;
            }
        }

        // 最左
        WordsPositionSearchResponse.Position.Coordinate minPoxCoordinate = minPoyCoordinate;
        for (WordsPositionSearchResponse.Position.Coordinate coordinate : coordinateList) {
            if (minPoyCoordinate.getPosx() > coordinate.getPosx()) {
                if (minPoyCoordinate.getPosy() >= coordinate.getPosy()) {
                    minPoxCoordinate = coordinate;
                }
            }
        }

        BaseSignFieldRequest.BaseSignfield.PosBean posBean = new BaseSignFieldRequest.BaseSignfield.PosBean();
        posBean.setPosPage(position.getPageIndex() + "");
        posBean.setPosX(minPoxCoordinate.getPosx());
        posBean.setPosY(minPoxCoordinate.getPosy());

        return posBean;
    }

    /**
     * 获取右下的关键字
     * @param position 位置
     * @return 关键字
     */
    private BaseSignFieldRequest.BaseSignfield.PosBean handleRightDownCoordinateList(WordsPositionSearchResponse.Position position) {
        List<WordsPositionSearchResponse.Position.Coordinate> coordinateList = position.getCoordinateList();
        // 最下
        WordsPositionSearchResponse.Position.Coordinate minPoyCoordinate = coordinateList.get(0);
        for (WordsPositionSearchResponse.Position.Coordinate coordinate : coordinateList) {
            if (minPoyCoordinate.getPosy() > coordinate.getPosy()) {
                minPoyCoordinate = coordinate;
            }
        }

        // 最右
        WordsPositionSearchResponse.Position.Coordinate minPoxCoordinate = minPoyCoordinate;
        for (WordsPositionSearchResponse.Position.Coordinate coordinate : coordinateList) {
            if (minPoyCoordinate.getPosx() < coordinate.getPosx()) {
                if (minPoyCoordinate.getPosy() >= coordinate.getPosy()) {
                    minPoxCoordinate = coordinate;
                }
            }
        }

        BaseSignFieldRequest.BaseSignfield.PosBean posBean = new BaseSignFieldRequest.BaseSignfield.PosBean();
        posBean.setPosPage(position.getPageIndex() + "");
        posBean.setPosX(minPoxCoordinate.getPosx());
        posBean.setPosY(minPoxCoordinate.getPosy());

        return posBean;
    }


    /**
     * 获取左下的关键字(一键签署)
     * @param position 位置
     * @return 关键字
     */
    private SignFlowCreateOneStepRequest.Signer.Signfield.PosBean handleOneStepLeftDownCoordinateList(WordsPositionSearchResponse.Position position) {
        List<WordsPositionSearchResponse.Position.Coordinate> coordinateList = position.getCoordinateList();
        // 最下
        WordsPositionSearchResponse.Position.Coordinate minPoyCoordinate = coordinateList.get(0);
        for (WordsPositionSearchResponse.Position.Coordinate coordinate : coordinateList) {
            if (minPoyCoordinate.getPosy() > coordinate.getPosy()) {
                minPoyCoordinate = coordinate;
            }
        }

        // 最左
        WordsPositionSearchResponse.Position.Coordinate minPoxCoordinate = minPoyCoordinate;
        for (WordsPositionSearchResponse.Position.Coordinate coordinate : coordinateList) {
            if (minPoyCoordinate.getPosx() > coordinate.getPosx()) {
                if (minPoyCoordinate.getPosy() >= coordinate.getPosy()) {
                    minPoxCoordinate = coordinate;
                }
            }
        }

        SignFlowCreateOneStepRequest.Signer.Signfield.PosBean posBean = new SignFlowCreateOneStepRequest.Signer.Signfield.PosBean();
        posBean.setPosPage(position.getPageIndex() + "");
        posBean.setPosX(minPoxCoordinate.getPosx());
        posBean.setPosY(minPoxCoordinate.getPosy());

        return posBean;
    }

    /**
     * 获取右下的关键字(一键签署)
     * @param position 位置
     * @return 关键字
     */
    private SignFlowCreateOneStepRequest.Signer.Signfield.PosBean handleOneStepRightDownCoordinateList(WordsPositionSearchResponse.Position position) {
        List<WordsPositionSearchResponse.Position.Coordinate> coordinateList = position.getCoordinateList();
        // 最下
        WordsPositionSearchResponse.Position.Coordinate minPoyCoordinate = coordinateList.get(0);
        for (WordsPositionSearchResponse.Position.Coordinate coordinate : coordinateList) {
            if (minPoyCoordinate.getPosy() > coordinate.getPosy()) {
                minPoyCoordinate = coordinate;
            }
        }

        // 最右
        WordsPositionSearchResponse.Position.Coordinate minPoxCoordinate = minPoyCoordinate;
        for (WordsPositionSearchResponse.Position.Coordinate coordinate : coordinateList) {
            if (minPoyCoordinate.getPosx() < coordinate.getPosx()) {
                if (minPoyCoordinate.getPosy() >= coordinate.getPosy()) {
                    minPoxCoordinate = coordinate;
                }
            }
        }

        SignFlowCreateOneStepRequest.Signer.Signfield.PosBean posBean = new SignFlowCreateOneStepRequest.Signer.Signfield.PosBean();
        posBean.setPosPage(position.getPageIndex() + "");
        posBean.setPosX(minPoxCoordinate.getPosx());
        posBean.setPosY(minPoxCoordinate.getPosy());

        return posBean;
    }
}